#-*- codeing = utf-8 -*-
#@Time : 2020/9/10 0:43
#@Author : 阳某
#@File : test1.py
#@Software : PyCharm
import threading
import time
from threading import Thread
# def xianyu():
#     print("咸鱼")
#     time.sleep(2)
# start_time = time.time()
# if __name__ == '__main__':
#     for i in range(5):
#         t = threading.Thread(target=xianyu)
#         t.start()
#     cost_time =time.time()-start_time
#     print(cost_time)    #0.0009989738464355469


# 使用Threading子类创建多线程
# class Mythread(threading.Thread):
#     def run(self):
#         for i in range(3):
#             time.sleep(2)
#             msg = "I'm " + self.name + ' @ ' + str(i)
#             print(msg)
# def test():
#     for i in range(5):
#         t = Mythread()
#         t.start()
# start_time = time.time()
# if __name__ == '__main__':
#     test()
#     # cost_time =time.time()-start_time     #主线程先结束（先打印时间，在执行子线程，无顺序执行)
#     # print(cost_time)
# # cost_time =time.time()-start_time    #主线程先结束（先打印时间，在执行子线程，无顺序执行)
# # print(cost_time)


# 在线程执行过程中，如果中途执行sleep语句时，线程进入到阻塞状态，当sleep结束之后，线程进入就绪状态，
# 等待调度而线程调度将自行选择一个线程执行
'''
# 线程之间共享全局变量
from threading import Thread
import time
num = 100
def work1():
    global num
    for i in range(3):
        num+=1
    print('----in work1 ,num is %d'%num)

def work2():
    global  num
    print('----in work2 ,num is %d'%num)
print('------线程之前g_num is %d-------'%num)
t1 = Thread(target=work1,)
t1.start()
#延时一会儿，保证t1线程中的事情做完
time.sleep(1)
t2 = Thread(target=work2,)
t2.start()
'''



# 线程不安全
# num = 0
# def test1():
#     global num
#     for i in range(1000000):
#         num+=1
#     print('-----test1----num=%d'%num)
# def test2():
#     global num
#     for i in range(1000000):
#         num+=1
#     print('-----test2---num=%d'%num)
# p1 = Thread(target=test1,)
# p1.start()
# time.sleep(3)     #注释之后时间很短
# p2 = Thread(target=test2,)
# p2.start()
# print("-----num=%d"%num)
'''
# time.sleep(3)     注释之后时间很短
-----num=244422
-----test1----num=1078833
-----test2---num=1321752

-----test1----num=1000000
-----num=1101123
-----test2---num=2000000

这个就是线程不安全的现象，线程1对数据num进行自增的时候，获取的值是num=0，此时系统把线程1调度为sleeping状态，
而线程2在做同样的操作时获取的num值还是0，同时做自增1的操作，这时在线程2中num的值为1，此时系统把线程2调度为sleeping状态，
线程1再做自增操作时，num还是刚刚获取到的0
'''

'''
避免线程不安全的现象
当多个线程几乎同时修改一个共享数据时，需要进行同步控制，线程同步能够保证多个线程安全访问竞争资源，
最简单的机智就是引入互斥锁，互斥锁为资源引入一个状态：锁定/非锁定
某个线程要更改数据时，先将其锁定，此时资源的状态为锁定，其它线程 不能更改，知道该线程释放资源，将资源的状态变成非锁定，
其他线程才能再次锁定该资源，互斥锁保证了每次只有一个线程进行写入操作，从而保证了多线程数据的正确性

当一个线程调用锁的acquire()方法获得锁时，锁就进入“locked”状态。每次只有一个线程可以获得锁。
如果此时另一个线程试图获得这个锁，该线程就会变为“blocked”状态，称为“阻塞”，
直到拥有锁的线程调用锁的release()方法释放锁之后，锁进入“unlocked”状态。
线程调度程序从处于同步阻塞状态的线程中选择一个来获得锁，并使得该线程进入运行状态。
from threading import Thread,Lock
num = 0
def test1():
    global num
    for i in range(10000000):
        # True 表示堵塞，即如果这个锁在上锁之前已经被上锁了，那么这个线程会在这里等待到解锁为止
        # False 表示非堵塞，即不管本次调用能否成功上锁，都不会卡在这，而是继续执行下面的代码
        mutexFlag = mutex.acquire(True)
        if mutexFlag:
            num +=1
            mutex.release()
    print("-----test1 -----num=%d"%num)

def test2():
    global num
    for i in range(10000000):
        # True 表示堵塞，即如果这个锁在上锁之前已经被上锁了，那么这个线程会在这里等待到解锁为止
        # False 表示非堵塞，即不管本次调用能否成功上锁，都不会卡在这，而是继续执行下面的代码
        mutexFlag = mutex.acquire(True)
        if mutexFlag:
            num +=1
            mutex.release()
    print("-----test2 -----num=%d"%num)
# 创建一个互斥锁，这个默认是未上锁的状态
mutex = Lock()
p1 = Thread(target=test1,)
p1.start()
p2 = Thread(target=test2,)
p2.start()
print("---num=%d"%num)

'''


'''
加锁确保了某段关键代码只能由一个线程从头到尾完整地执行，但是阻止了多线程并发执行，包含锁的某段代码实际上只能以单线程模式执行，
效率就大大地下降了，由于可以存在多个锁，不同的线程持有不同的锁，并试图获取对方持有的锁时，可能会造成死锁
在线程间共享多个资源的时候，如果两个线程分别占有一部分资源并且同时等待对方的资源，就会造成死锁。
class Mythread1(threading.Thread):
    def run(self) -> None:
        if mutexA.acquire():
            print(self.name+'------do1---up-----')
            time.sleep(1)
            if mutexB.acquire():
                print(self.name + '------do1---down-----')
                mutexB.release()
            mutexA.release()
class Mythread2(threading.Thread):
    def run(self) -> None:
        if mutexB.acquire():
            print(self.name+'------do2---up-----')
            time.sleep(1)
            if mutexA.acquire():
                print(self.name + '------do2---down-----')
                mutexA.release()
            mutexB.release()

mutexA = threading.Lock()
mutexB = threading.Lock()

if __name__ == '__main__':  #死锁
    t1 = Mythread1()
    t1.start()
    t2 = Mythread2()
    t2.start()
'''
from threading import Thread,Lock




